﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Media;
using System.Xml.Linq;

namespace ComicTool.Drawing.Svg
{
    public class TextInfo
    {
        private readonly IFormatProvider format = CultureInfo.InvariantCulture.NumberFormat;
        public bool addDescent;
        public Brush fill;
        public string fontFamily;
        public float fontSize;
        public FontStyle fontStyle;
        public FontWeight fontWeight;
        public TransformGroup group = new TransformGroup();
        public bool preserveWS;
        public Brush strokeBrush;
        public Thickness strokeThickness;
        public FlowDirection textDirection = FlowDirection.LeftToRight;
        public bool vertical;
        //public StringAlignment lineAlignment;

        public TextInfo Clone()
        {
            var ti = MemberwiseClone() as TextInfo;
            ti.group = new TransformGroup();
            ti.group.Children.AddRange(ti.group.Children);
            return ti;
        }

        //public static TextInfo Default
        //{
        //    get
        //    {
        //        TextInfo info;
        //        info.preserveWS = false;
        //        info.fill = null;
        //        info.stroke = null;
        //        info.group = new TransformGroup();
        //        info.fontFamily = "sans";
        //        info.fontSize = 10f;
        //        info.fontWeight = FontWeights.Normal;
        //        info.fontStyle = FontStyles.Normal;
        //        info.vertical = false;
        //        info.rightToLeft = false;
        //        //info.lineAlignment = StringAlignment.Far;
        //        info.addDescent = true;
        //        return info;
        //    }
        //}

        public void LoadInfo(ICollection<XAttribute> nav)
        {
            string val;

            val = nav.GetAttributeValue("space");
            if (val != "")
            {
                preserveWS = val == "preserve";
            }

            val = nav.GetAttributeValue("fill");
            if (val != "")
            {
                if (val == "none")
                {
                    fill = null;
                }
                else
                {
                    fill = new SolidColorBrush(ParseRgb(val));
                }
            }

            val = nav.GetAttributeValue("stroke");
            if (val != "")
            {
                if (val == "none")
                {
                    strokeBrush = null;
                }
                else
                {
                    float width = 1.0f;
                    string strokeWidth = nav.GetAttributeValue("stroke-width");
                    if (strokeWidth != "")
                    {
                        width = float.Parse(strokeWidth, format);
                    }
                    strokeBrush = new SolidColorBrush(ParseRgb(val));
                    strokeThickness = new Thickness(width);
                }
            }

            ParseXY(nav);
            ParseTransform(nav);

            val = nav.GetAttributeValue("font-family");
            if (val != "")
            {
                fontFamily = val;
            }

            val = nav.GetAttributeValue("font-size");
            if (val != "")
            {
                fontSize = float.Parse(val, format);
            }

            val = nav.GetAttributeValue("font-weight");
            if (val != "")
            {
                if (val == "normal")
                {
                    fontWeight = FontWeights.Normal;
                }
                else if (val == "bold")
                {
                    fontWeight = FontWeights.Bold;
                }
            }

            val = nav.GetAttributeValue("font-style");
            if (val != "")
            {
                if (val == "normal")
                {
                    fontStyle = FontStyles.Normal;
                }
                else if (val == "italic")
                {
                    fontStyle = FontStyles.Italic;
                }
            }

            val = nav.GetAttributeValue("writing-mode");
            if (val != "")
            {
                switch (val)
                {
                    default:
                    case "lr":
                        vertical = false;
                        textDirection = FlowDirection.LeftToRight;
                        addDescent = true;
                        break;
                    case "rl":
                        vertical = false;
                        textDirection = FlowDirection.RightToLeft;
                        addDescent = true;
                        break;
                    case "tb":
                        vertical = true;
                        addDescent = false;
                        break;
                }
            }

            val = nav.GetAttributeValue("glyph-orientation-vertical");
            if (val != "")
            {
                // Not supported.
            }

            //val = nav.Attribute("dominant-baseline").Value;
            //if (val != "")
            //    switch (val)
            //    {
            //        case "alphabetic":
            //        default:
            //            lineAlignment = StringAlignment.Far;
            //            addDescent = true;
            //            break;
            //        case "middle":
            //            lineAlignment = StringAlignment.Center;
            //            addDescent = false;
            //            break;
            //        case "text-after-edge":
            //            lineAlignment = StringAlignment.Far;
            //            addDescent = false;
            //            break;
            //        case "text-before-edge":
            //            lineAlignment = StringAlignment.Near;
            //            addDescent = false;
            //            break;
            //    }
        }

        private void ParseXY(ICollection<XAttribute> nav)
        {
            string x = nav.GetAttributeValue("x");
            double tx = 0;
            string y = nav.GetAttributeValue("y");
            double ty = 0;

            if (!x.IsNullOrEmpty())
            {
                tx = double.Parse(x, format);
            }
            if (!y.IsNullOrEmpty())
            {
                ty = double.Parse(y, format);
            }
            if (ty != 0 || tx != 0)
            {
                group.Children.Add(new TranslateTransform
                {
                    X = tx,
                    Y = ty,
                });
            }
        }

        private void ParseTransform(ICollection<XAttribute> nav)
        {
            string val = nav.GetAttributeValue("transform");
            if (val != "")
            {
                string[] tokens = val.Replace("(", " ( ").Replace(")", " ) ").Split(new[] { ' ', ',' },
                                                                                    StringSplitOptions.
                                                                                        RemoveEmptyEntries);

                for (int i = 0; i < tokens.Length; i++)
                {
                    switch (tokens[i])
                    {
                        case "matrix":
                            if (tokens[i + 1] != "(" || tokens[i + 8] != ")")
                            {
                                break;
                            }
                            var m = new Matrix(float.Parse(tokens[i + 2], format),
                                               float.Parse(tokens[i + 3], format),
                                               float.Parse(tokens[i + 4], format),
                                               float.Parse(tokens[i + 5], format),
                                               float.Parse(tokens[i + 6], format),
                                               float.Parse(tokens[i + 7], format));
                            group.Children.Add(new MatrixTransform
                            {
                                Matrix = m
                            });
                            i += 8;
                            break;
                        case "translate":
                            if (tokens[i + 1] != "(")
                            {
                                break;
                            }
                            if (tokens[i + 3] == ")")
                            {
                                float x = float.Parse(tokens[i + 2], format);
                                float y = float.Parse(tokens[i + 2], format);
                                group.Children.Add(new TranslateTransform
                                {
                                    X = x,
                                    Y = y,
                                });
                                i += 3;
                            }
                            else if (tokens[i + 4] == ")")
                            {
                                float x = float.Parse(tokens[i + 2], format);
                                float y = float.Parse(tokens[i + 3], format);
                                group.Children.Add(new TranslateTransform
                                {
                                    X = x,
                                    Y = y,
                                });
                                i += 4;
                            }
                            break;
                        case "scale":
                            if (tokens[i + 1] != "(")
                            {
                                break;
                            }
                            if (tokens[i + 3] == ")")
                            {
                                float scale = float.Parse(tokens[i + 2], format);
                                group.Children.Add(new ScaleTransform
                                {
                                    ScaleX = scale,
                                    ScaleY = scale,
                                });
                                i += 3;
                            }
                            else if (tokens[i + 4] == ")")
                            {
                                float scaleX = float.Parse(tokens[i + 2], format);
                                float scaleY = float.Parse(tokens[i + 3], format);
                                group.Children.Add(new ScaleTransform
                                {
                                    ScaleX = scaleX,
                                    ScaleY = scaleY,
                                });
                                i += 4;
                            }
                            break;
                        case "rotate":
                            if (tokens[i + 1] != "(")
                            {
                                break;
                            }
                            if (tokens[i + 3] == ")")
                            {
                                group.Children.Add(new RotateTransform
                                {
                                    Angle = float.Parse(tokens[i + 2], format)
                                });
                                i += 3;
                            }
                            else if (tokens[i + 5] == ")")
                            {
                                group.Children.Add(new RotateTransform
                                {
                                    Angle = float.Parse(tokens[i + 2], format),
                                    CenterX = float.Parse(tokens[i + 3], format),
                                    CenterY = float.Parse(tokens[i + 4], format),
                                });
                                i += 5;
                            }
                            break;
                        case "skewX":
                            if (tokens[i + 1] != "(" || tokens[i + 3] != ")")
                            {
                                break;
                            }
                            var angleX = (float)Math.Tan(double.Parse(tokens[i + 2], format) / 180 * Math.PI);
                            group.Children.Add(new SkewTransform
                            {
                                AngleX = angleX
                            });
                            i += 3;
                            break;
                        case "skewY":
                            if (tokens[i + 1] != "(" || tokens[i + 3] != ")")
                            {
                                break;
                            }
                            var angleY = (float)Math.Tan(double.Parse(tokens[i + 2], format) / 180 * Math.PI);
                            group.Children.Add(new SkewTransform
                            {
                                AngleY = angleY
                            });
                            i += 3;
                            break;
                    }
                }
            }
        }

        internal static Color ParseRgb(string rgb)
        {
            string[] tokens = rgb.Split(' ', '(', ',', ')');
            if (tokens[0] != "rgb")
            {
                throw new ArgumentException();
            }
            return Color.FromArgb(0xFF, byte.Parse(tokens[1]), byte.Parse(tokens[2]), byte.Parse(tokens[3]));
        }
    }
}
